interface RequestOptions {
    url: string
    headers?: Record<string, string>
    method?: HttpMethod
    data?: Record<string, any>
    timeout?: number
    retries?: number
    cache?: boolean
    cacheTime?: number // 秒
}

// 简化的缓存与请求去重
const requestCache = new Map<string, { data: any; expiry: number }>()
const pendingRequests = new Map<string, Promise<any>>()

const generateKey = (options: RequestOptions): string => `${options.method || 'POST'}_${options.url}_${JSON.stringify(options.data || {})}`

const cleanCache = () => {
    const now = Date.now()
    for (const [key, item] of requestCache.entries()) {
        if (now > item.expiry) requestCache.delete(key)
    }
}

// 统一的错误映射
const toApiError = (raw: any, fallback: Partial<ApiError> = {}): ApiError => {
    const isNetwork = !raw || raw.errMsg || raw instanceof Error
    const message = (raw && (raw.message || raw.msg)) || (typeof raw === 'string' ? raw : '') || fallback.message || '请求失败，请稍后重试'
    return {
        type: isNetwork ? 'NETWORK' : 'BUSINESS',
        message,
        statusCode: raw?.statusCode,
        code: raw?.code,
        details: raw
    }
}

export const request = {
    async http<T = any>({
        url = '',
        headers = {},
        data = {},
        method = 'POST',
        timeout = 10000,
        retries = 2,
        cache = false,
        cacheTime = 300
    }: RequestOptions): Promise<ApiResponse<T>> {
        const requestKey = generateKey({ url, method, data })

        // 命中缓存（仅GET）
        if (cache && method === 'GET') {
            cleanCache()
            const cached = requestCache.get(requestKey)
            if (cached && Date.now() < cached.expiry) return Promise.resolve(cached.data)
        }

        // 去重
        if (pendingRequests.has(requestKey)) return pendingRequests.get(requestKey)!

        // 构建完整URL
        const fullUrl = (() => {
            // #ifdef APP-PLUS || MP-WEIXIN
            return import.meta.env.VITE_APP_BASE_URL + url
            // #endif
            // #ifdef H5
            return import.meta.env.MODE === 'development' ? import.meta.env.VITE_APP_BASE_PRE + url : import.meta.env.VITE_APP_BASE_URL + url
            // #endif
        })()

        // 统一请求头
        const header = {
            'content-type': 'application/json',
            // TODO: 从store动态获取token，这里临时保留以便尚未接入后端时调试
            token: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJtZW1iZXJfaWQiOjIyLCJ1c2VybmFtZSI6IjE5OTY5MDEzNTYxIiwiaXNzIjoibG50LnRydWVzY2xvdWQuY29tIiwiYXVkIjoibG50LnRydWVzY2xvdWQuY29tIiwiaWF0IjoxNzU0ODgzNTkyLCJuYmYiOjE3NTQ4ODM1OTIsImV4cCI6MTc1NTQ4ODM5MiwianRpIjoiMjJfYXBpIn0.n2Kh4sJu1Bkpw9t9fWuX1vI8Mqh9f5p_yT4uHiahF5s',
            ...headers
        }

        const requestPromise: Promise<ApiResponse<T>> = new Promise((resolve, reject) => {
            const makeRequest = (attempt = 0): void => {
                uni.request({
                    url: fullUrl,
                    header,
                    method,
                    data,
                    timeout,
                    success(res) {
                        const { statusCode } = res
                        const response = res.data as ApiResponse<T>
                        const code = response?.code
                        const ok = [1, 200].includes(code as number)

                        // HTTP层错误（如 404/500）
                        if (statusCode && statusCode >= 400) {
                            const err: ApiError = { type: 'HTTP', message: `HTTP ${statusCode}`, statusCode }
                            uni.showToast({ title: '网络繁忙，请稍后再试', icon: 'none' })
                            reject(err)
                            return
                        }

                        // 成功与业务错误
                        if (ok) {
                            // 缓存GET
                            if (cache && method === 'GET') {
                                requestCache.set(requestKey, { data: response, expiry: Date.now() + cacheTime * 1000 })
                            }
                            resolve(response)
                        } else if (code === 1005) {
                            uni.showToast({ title: '登录已失效', icon: 'none' })
                            setTimeout(() => uni.navigateTo({ url: '/pages/login/login' }), 800)
                            reject({ type: 'BUSINESS', message: response?.message || response?.msg || '登录失效', code })
                        } else {
                            const msg = response?.message || response?.msg || '请求失败'
                            uni.showToast({ title: msg, icon: 'none' })
                            reject({ type: 'BUSINESS', message: msg, code })
                        }
                    },
                    fail(err) {
                        if (attempt < (retries || 0)) {
                            setTimeout(() => makeRequest(attempt + 1), 1000 * (attempt + 1))
                        } else {
                            const apiError = toApiError(err, { type: 'NETWORK', message: '网络错误' })
                            uni.showToast({ title: apiError.message, icon: 'none' })
                            reject(apiError)
                        }
                    },
                    complete() {
                        pendingRequests.delete(requestKey)
                    }
                })
            }
            makeRequest()
        })

        pendingRequests.set(requestKey, requestPromise)
        return requestPromise
    },

    // 清除缓存
    clearCache(url?: string) {
        if (url) {
            for (const [key] of requestCache.entries()) {
                if (key.includes(url)) requestCache.delete(key)
            }
        } else {
            requestCache.clear()
        }
    }
}
